import { Tabs } from "nextra/components";

import RemoteSource from "../../../components/RemoteSource";
import { YoutubeRenderer } from "../../../components/YoutubeRenderer";


## Shopping AI Chatbot

<br/>
<YoutubeRenderer src="https://www.youtube.com/embed/RAzYo02HTXA" type="shorts"/>

  - Github Repository: https://github.com/samchon/shopping-backend
  - Architecture: [Entity Relationship Diagram](https://github.com/samchon/shopping-backend/blob/master/docs/ERD.md)
  - Swagger UI: https://shopping-be.wrtn.ai/editor
  - Playground: https://wrtnlabs.io/agentica/playground/shopping/

Shopping backend server project for enterprise level chatbot demonstration.

[`@samchon/shopping-backend`](https://github.com/samchon/shopping-backend) is a shopping mall backend server project consisting of a total of 289 API functions which can cover most features of e-commerce. And it was created to prove that `@agentica` developed agent is suitable for enterprise level projects.

The `@samchon/shopping-backend` projects shows the best practice of a backend development with LLM agent utilization in mind. Following the [Compiler Driven Development](/docs/concepts/compiler-driven-development) and [Document Drive Development](/docs/concepts/document-driven-development) rules, each API function is appropriately commented to explain its purpose, and DTO types are precisely defined and clearly explained through comments. All of these aspects are consistently measured and improved through the benchmark with [`@agentica/benchmark`](/docs/plugins/benchmark) module.

If you're considering to develop an enterprise level chatbot, `@samchon/shopping-backend` is the best reference to start with. Traveling its [repository](https://github.com/samchon/shopping-backend) and looking at its source codes, you can learn how to accomplish the ideal backend development for chatbot projects following the [Document Driven Development](/docs/concepts/document-driven-development) paradigm.




## Authentication
<Tabs items={["Conceptual Code", "Actual Code"]}>
<Tabs.Tab>
```typescript filename="src/main.ts" showLineNumbers {18-22}
import { Agentica, assertHttpController } from "@agentica/core";
import OpenAI from "openai";

const agent = new Agentica({
  model: "chatgpt",
  vendor: {
    model: "gpt-4o-mini",
    api: new OpenAI({ apiKey: "********" }),
  },
  controllers: [
    assertHttpController({
      name: "shopping",
      model: "chatgpt",
      document: await fetch(
        "https://shopping-be.wrtn.ai/editor/swagger.json",
      ).then((res) => res.json()),
      connection: {
        host: "https://shopping-be.wrtn.ai",
        headers: {
          Authorization: "Bearer ********",
        },
      },
    }),
  ],
});
await agent.convert("I wanna buy a Macbook.");
```
  </Tabs.Tab>
  <Tabs.Tab>
```typescript filename="src/main.ts" showLineNumbers {2, 5-28, 45}
import { Agentica, assertHttpController } from "@agentica/core";
import ShoppingApi from "@samchon/shopping-api";
import OpenAI from "openai";

// Authentication to the shopping backend server
const connection: ShoppingApi.IConnection = {
  host: "https://shopping-be.wrtn.ai",
};
await ShoppingApi.functional.shoppings.customers.authenticate.create(
  connection,
  {
    channel_code: "samchon",
    external_user: null,
    href: window.location.href,
    referrer: window.document.referrer,
  },
);
await ShoppingApi.functional.shoppings.customers.authenticate.activate(
  connection,
  {
    mobile: "010-1234-5678",
    name: "John Doe",
  },
);

// Bearer ********
// Nestia SDK injected the Authorization header
console.log(connection.headers?.Authorization);

// Agentica with authenticated connection
const agent = new Agentica({
  model: "chatgpt",
  vendor: {
    model: "gpt-4o-mini",
    api: new OpenAI({ apiKey: "********" }),
  },
  controllers: [
    assertHttpController({
      name: "shopping",
      model: "chatgpt",
      document: await fetch(
        "https://shopping-be.wrtn.ai/editor/swagger.json",
      ).then((res) => res.json()),
      connection,
    }),
  ],
});
await agent.convert("I wanna buy a Macbook.");
```
  </Tabs.Tab>
</Tabs>

Authentication before agent construction.

One of the characteristics of [`@samchon/shopping-backend`](https://github.com/samchon/shopping-backend) is that user authentication must be performed in advance before API function calling via the chatbot. If the user is not authenticated, the API function will throw 403 forbidden error. 

Even though it is possible to make agent to call the authentication function before than any others by system prompting, but there can be some applications not to do so like `@samchon/shopping-backend`. The representative example of such case is the membership chatbot, which is opened only for the membership users.

In that case, you have to authenticate like above before the agent construction.




## Document Driven Development
<Tabs items={[
  <code>ShoppingSaleController</code>,
  <code>IShoppingSaleUnitStock</code>,
  <code>IShoppingSaleUnitSelectableOption</code>,
]}>
  <Tabs.Tab>
```typescript filename="@samchon/shopping-backend/ShoopingSaleController" showLineNumbers
import core from "@nestia/core";
import { Controller } from "@nestjs/common";
import { RouteIcon } from "@wrtnio/decorators";
import { tags } from "typia";
 
import { IPage } from "@samchon/shopping-api/lib/structures/common/IPage";
import { IShoppingActorEntity } from "@samchon/shopping-api/lib/structures/shoppings/actors/IShoppingActorEntity";
import { IShoppingSale } from "@samchon/shopping-api/lib/structures/shoppings/sales/IShoppingSale";
 
import { ShoppingSaleProvider } from "../../../../providers/shoppings/sales/ShoppingSaleProvider";
import { IShoppingControllerProps } from "../IShoppingControllerProps";
 
export function ShoppingSaleController<Actor extends IShoppingActorEntity>(
  props: IShoppingControllerProps,
) {
  @Controller(`shoppings/${props.path}/sales`)
  abstract class ShoppingSaleController {
    /**
     * List up every summarized sales.
     *
     * List up every {@link IShoppingSale.ISummary summarized sales}.
     *
     * As you can see, returned sales are summarized, not detailed. It does not
     * contain the SKU (Stock Keeping Unit) information represented by the
     * {@link IShoppingSaleUnitOption} and {@link IShoppingSaleUnitStock} types.
     * If you want to get such detailed information of a sale, use
     * `GET /shoppings/customers/sales/{id}` operation for each sale.
     *
     * > If you're an A.I. chatbot, and the user wants to buy or compose
     * > {@link IShoppingCartCommodity shopping cart} from a sale, please
     * > call the `GET /shoppings/customers/sales/{id}` operation at least once
     * > to the target sale to get detailed SKU information about the sale.
     * > It needs to be run at least once for the next steps.
     *
     * @param input Request info of pagination, searching and sorting
     * @returns Paginated sales with summarized information
     * @tag Sale
     *
     * @author Samchon
     */
    @RouteIcon(
      "https://ecosystem-connector.s3.ap-northeast-2.amazonaws.com/icons/store.svg",
    )
    @core.TypedRoute.Patch()
    public async index(
      @props.AuthGuard() actor: Actor,
      @core.TypedBody() input: IShoppingSale.IRequest,
    ): Promise<IPage<IShoppingSale.ISummary>> {
      return ShoppingSaleProvider.index({
        actor,
        input,
      });
    }
 
    /**
     * Get a sale with detailed information.
     *
     * Get a {@link IShoppingSale sale} with detailed information including
     * the SKU (Stock Keeping Unit) information represented by the
     * {@link IShoppingSaleUnitOption} and {@link IShoppingSaleUnitStock} types.
     *
     * > If you're an A.I. chatbot, and the user wants to buy or compose a
     * > {@link IShoppingCartCommodity shopping cart} from a sale, please call
     * > this operation at least once to the target sale to get detailed SKU
     * > information about the sale.
     * >
     * > It needs to be run at least once for the next steps. In other words,
     * > if you A.I. agent has called this operation to a specific sale, you
     * > don't need to call this operation again for the same sale.
     * >
     * > Additionally, please do not summarize the SKU information. Just show
     * > the every options and stocks in the sale with detailed information.
     *
     * @param id Target sale's {@link IShoppingSale.id}
     * @returns Detailed sale information
     * @tag Sale
     *
     * @author Samchon
     */
    @core.TypedRoute.Get(":id")
    public async at(
      @props.AuthGuard() actor: Actor,
      @core.TypedParam("id") id: string & tags.Format<"uuid">,
    ): Promise<IShoppingSale> {
      return ShoppingSaleProvider.at({
        actor,
        id,
      });
    }
  }
  return ShoppingSaleController;
}
```
  </Tabs.Tab>
  <Tabs.Tab>
    <RemoteSource 
      url="https://raw.githubusercontent.com/samchon/shopping-backend/refs/heads/master/src/api/structures/shoppings/sales/IShoppingSaleUnitStock.ts" 
      filename="@samchon/shopping-backend/IShoppingSaleUnitStock" 
      showLineNumbers />
  </Tabs.Tab>
  <Tabs.Tab>
    <RemoteSource 
      url="https://raw.githubusercontent.com/samchon/shopping-backend/refs/heads/master/src/api/structures/shoppings/sales/IShoppingSaleUnitSelectableOption.ts" 
      filename="@samchon/shopping-backend/IShoppingSaleUnitSelectableOption" 
      showLineNumbers />
  </Tabs.Tab>
</Tabs>

Documentation comments on API controllers and DTO types.

[`@samchon/shopping-backend`](https://github.com/samchon/shopping-backend) has 289 number of API functions, and they can be classified into 10 categories of below. If trying to make such shopping chatbot by traditional way utilizing agent graph and workflow, it would be a very hard and time-consuming task. Number of function calling sequence is infinite (2<sup>289</sup>-1), and number of secnario is also infinite.

To make properly working chatbot, only the way is to following the `@agentica`'s function calling strategy with [Document Drive Development](/docs/concepts/document-driven-development) paradigm. And `@samchon/openapi` has tried to write accurate and precise comments on every API functions and DTO (Data Transfer Object) types like above.

By writing the purpose of each function and DTO type independently, you can avoid huge system prompts and workflow graphs that extend to infinite cases. This is how enterprise-grade chatbots with a large number of functions should be built.

  - Categories of API functions
    - systematic
    - sale (product)
    - shopping cart
    - order appliance
    - payment
    - refund
    - question/review
    - discount coupon
    - bonus coin
    - deposit






## Benchmarking
> I wanna see every sales in the shopping mall
> 
> And then show me the detailed information about the Macbook.
> 
> After that, select the most expensive stock from the Macbook, and put it into my shopping cart. And take the shopping cart to the order.
> 
> At last, I'll publish it by cash payment, and my address is
> 
>   - country: South Korea
>   - city/province: Seoul
>   - department: Wrtn Apartment
>   - Possession: 101-1411

Benchmark for the estimation.

[`@samchon/shopping-backend`](https://github.com/samchon/shopping-backend) has increased the chatbot quality by benchmarking the chatbot with the above like scenarios. As `@samchon/shopping-backend` has 289 number of API functions, and its number of combination is infinite (2<sup>289</sup>-1), it is hard to ensure the quality of the chatbot by manual testing.

Therefore, `@samchon/shopping-backend` has estimated and evolved the documentation comments of API functions and DTO (Data Transfer Object) types, so that tried to ensure the chatbot quality by the benchmarking with [`@agentica/benchmark`](/docs/plugins/benchmark) module. And in actually, the shopping chatbot quality has been improved dramatically.

Have you seen any similar level chatbot of such quality? If you're developing enterprise level backend system and it would be utilized in the chatbot by function calling, you'd better to follow the [Document Driven Development](/docs/concepts/document-driven-development) paradigm, and it must be benchmarked to ensure the quality of the chatbot. Then you can do the same thing as `@samchon/shopping-backend`.

